package com.dt.common.validation.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.dt.common.validation.Validator;
import com.dt.common.validation.Violation;
import com.dt.common.validation.itf.ConstraintValidation;
import com.dt.common.validation.itf.RuntimeConfiguration;
import com.dt.common.validation.itf.ValidatioinBuilder;
import com.dt.common.validation.itf.ValidationDefinition;

public class DefaultValidator implements Validator {

	private RuntimeConfiguration configuration;

	private Map<ValidationDefinition, ConstraintValidation> validations = new HashMap<>();

	public DefaultValidator(RuntimeConfiguration configuration, ObjectValidationDefinition objectValidationDefinition) {
		this.configuration = configuration;

		for (ValidationDefinition validationDefinition : objectValidationDefinition.getDefinitions()) {
			if (validationDefinition instanceof ValidatioinBuilder) {
				ConstraintValidation validation = ((ValidatioinBuilder) validationDefinition).buildValidation();
				validations.put(validationDefinition, validation);
			}
		}
	}

	@Override
	public Set<Violation> validate(Object object) {
		DefaultValidationContext context = new DefaultValidationContext();
		context.setConfiguration(this.configuration);

		for (Entry<ValidationDefinition, ConstraintValidation> entry : validations.entrySet()) {
			Object propertyValue = entry.getKey().getPropertyGetter().get(object);
			boolean isValid = entry.getValue().isValid(context, object, propertyValue);
			if (!isValid) {
				buildViolation(entry.getKey(), context, object, propertyValue);
			}
			if (configuration.isFastFailure() && !isValid) {
				break;
			}
		}

		return context.getViolations();
	}

	@Override
	public Set<Violation> validate(Object object, String propertyName) {
		DefaultValidationContext context = new DefaultValidationContext();
		context.setConfiguration(this.configuration);

		for (Entry<ValidationDefinition, ConstraintValidation> entry : validations.entrySet()) {
			if (entry.getKey().getPropertyName().equals(propertyName)) {
				Object propertyValue = entry.getKey().getPropertyGetter().get(object);
				boolean isValid = entry.getValue().isValid(context, object, propertyValue);

				if (!isValid) {
					buildViolation(entry.getKey(), context, object, propertyValue);
				}

				if (configuration.isFastFailure() && !isValid) {
					break;
				}
			}
		}

		return context.getViolations();
	}

	private void buildViolation(ValidationDefinition definition, DefaultValidationContext context, Object objectValue,
			Object propertyValue) {
		DefaultViolation violation = new DefaultViolation(definition);
		violation.setCheckedBean(objectValue);
		violation.setInvalidValue(propertyValue);
		violation.setMsg(definition.getResolvedMsg());

		context.addViolation(violation);
	}

}
